﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Transactions;
using System.Web.Hosting;
using PAMD.Database.Model;
using System.Data.Objects;

namespace PAMD.Database.Services
{
    [Export(typeof(ListingService))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class ListingService
    {
        readonly PAMDEntities _contexts = new PAMDEntities();

        public ListingService()
        {
            _contexts.ListingFeatures.MergeOption = MergeOption.OverwriteChanges;
            _contexts.ListingPhotoes.MergeOption = MergeOption.OverwriteChanges;
            _contexts.ListingPrices.MergeOption = MergeOption.OverwriteChanges;
            _contexts.Listings.MergeOption = MergeOption.OverwriteChanges;
            _contexts.Occupations.MergeOption = MergeOption.OverwriteChanges;
            _contexts.Registrations.MergeOption = MergeOption.OverwriteChanges;
            _contexts.UserDetails.MergeOption = MergeOption.OverwriteChanges;
            _contexts.Addresses.MergeOption = MergeOption.OverwriteChanges;
            _contexts.Countries.MergeOption = MergeOption.OverwriteChanges;
        }

        public UserDetail GetByUserName(string username)
        {
            var loweUserName = username.Trim().ToLower();
            bool found = _contexts.UserDetails.Any(u => u.Email == loweUserName);
            if (found)
            {
                return _contexts.UserDetails.First(u => u.Email == loweUserName);
            }
            return null;
        }

        public int AddNewListing(UserDetail userAccount, Listing listing, List<ListingPrice> listingPrice, Address address, List<string> pictures)
        {
            if (listingPrice.Count < 1)
            {
                return 0;
            }
            using (TransactionScope scope = new TransactionScope())
            {
                address.UserID = userAccount.ID;
                address.AddressType = AddressType.Listing.ToString();
                _contexts.Addresses.AddObject(address);
                _contexts.SaveChanges();

                listing.UserID = userAccount.ID;
                listing.AddressID = address.ID;
                listing.IsActive = true;

                _contexts.Listings.AddObject(listing);
                _contexts.SaveChanges();

                foreach (var lstPrice in listingPrice)
                {
                    lstPrice.ListingID = listing.ID;
                    _contexts.ListingPrices.AddObject(lstPrice);
                }

                //First picture will be primary picture.
                bool first = true;
                foreach (var pics in pictures)
                {
                    _contexts.ListingPhotoes.AddObject(new ListingPhoto { FileName = pics, IsPrimary = first, ListingID = listing.ID });
                    first = false;
                }

                _contexts.SaveChanges();

                scope.Complete();
            }
            return listing.ID;
        }
        public Address GetAddreess(int addressId)
        {
            bool found = _contexts.Addresses.Any(a => a.ID == addressId);
            if (found)
            {
                return _contexts.Addresses.First(a => a.ID == addressId);
            }

            return null;
        }

        public List<ListingResult> GetAllListing(UserDetail userDetail)
        {
            var listings = (from l in _contexts.Listings
                            where l.UserID == userDetail.ID
                            join a in _contexts.Addresses on l.AddressID equals a.ID into la
                            from subaddr in la.DefaultIfEmpty()
                            join p in _contexts.ListingPhotoes on l.ID equals p.ListingID into lp
                            join price in _contexts.ListingPrices on l.ID equals price.ListingID into lprice
                            select new ListingResult { Listing = l, Address = subaddr, Photo = lp.DefaultIfEmpty(), Price = lprice.DefaultIfEmpty() }).ToList();

            return listings;
        }

        public ListingResult GetListing(int ListingID)
        {
            var listing = (from l in _contexts.Listings
                           where l.ID == ListingID
                           join a in _contexts.Addresses on l.AddressID equals a.ID into la
                           from subaddr in la.DefaultIfEmpty()
                           join p in _contexts.ListingPhotoes on l.ID equals p.ListingID into lp
                           join price in _contexts.ListingPrices on l.ID equals price.ListingID into lprice
                           select new ListingResult { Listing = l, Address = subaddr, Photo = lp.DefaultIfEmpty(), Price = lprice.DefaultIfEmpty() }).FirstOrDefault();

            return listing;
        }

        public int UpdateListing(UserDetail userAccount, Listing listing, List<ListingPrice> listingPrice, Address address, List<string> pictures)
        {
            if (listingPrice.Count < 1)
            {
                return 0;
            }
            using (TransactionScope scope = new TransactionScope())
            {
                address.UserID = userAccount.ID;
                address.AddressType = AddressType.Listing.ToString();
                var dbListing = _contexts.Listings.FirstOrDefault(l => l.ID == listing.ID);
                listing.ID = dbListing.ID;

                var dbAddress = _contexts.Addresses.AsEnumerable().FirstOrDefault(a => (a.ID == dbListing.AddressID) && (Utils.GetEnumVal<AddressType>(a.AddressType) == AddressType.Listing));

                if (dbAddress == null)
                {
                    _contexts.Addresses.AddObject(address);
                    dbAddress = address;
                }
                else
                {
                    address.ID = dbAddress.ID;
                    _contexts.Addresses.ApplyCurrentValues(address);
                }

                _contexts.SaveChanges();

                listing.UserID = userAccount.ID;
                listing.AddressID = address.ID;
                listing.IsActive = true;

                _contexts.Listings.ApplyCurrentValues(dbListing);

                _contexts.SaveChanges();

                foreach (var lp in _contexts.ListingPrices.Where(p => p.ListingID == dbListing.ID))
                {
                    if (listingPrice.Any(l => l.ID == lp.ID))
                    {
                        _contexts.ListingPrices.ApplyCurrentValues(listingPrice.First(l => l.ID == lp.ID));
                    }
                    else
                    {
                        _contexts.ListingPrices.DeleteObject(lp);
                    }
                }

                foreach (var lstPrice in listingPrice.Where(lp => lp.ID == 0))
                {
                    lstPrice.ListingID = listing.ID;
                    _contexts.ListingPrices.AddObject(lstPrice);
                }

                _contexts.SaveChanges();

                foreach (var lp in _contexts.ListingPhotoes.Where(p => p.ListingID == dbListing.ID))
                {
                    _contexts.ListingPhotoes.DeleteObject(lp);
                }

                //First picture will be primary picture.
                bool first = true;
                foreach (var pics in pictures)
                {
                    _contexts.ListingPhotoes.AddObject(new ListingPhoto { FileName = pics, IsPrimary = first, ListingID = listing.ID });
                    first = false;
                }

                _contexts.SaveChanges();

                scope.Complete();
            }
            return listing.ID;
        }
    }
}